#include <stdbool.h>
#include <errno.h>
#include <error.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <time.h>
#include <sys/wait.h>
#include <dirent.h>
#include <syslog.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <sys/time.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <sys/sendfile.h>

/**************************************************************************************
 *          配置文件调用函数
 * *************************************************************************************/
int getparameter(char *key, char *value);
//配置文件函数使用方法:
//所有的传出参数都定义为char*或者char[],ip和端口分别要使用inet_addr和atoi进行解析.
//数据库的部分可以后面通过修改配置文件增加数据库的账号密码部分
//如果不知道具体名称,可以打开对应的配置文件config.ini查看有哪些k-v值

/***************************************************************************************
 *                                   队列部分									   *
 ***************************************************************************************/
// 定义队列结点
typedef struct node_s {
	int net_fd;
	struct node_s* pNext;
}node_t;

// 定义队列
typedef struct queue_s {
	node_t* head;
	node_t* end;
	int size;
}queue_t;

//入队
int enQueue(queue_t* pQueue, int net_fd);
//出队
int deQueue(queue_t* pQueue);


/***************************************************************************************
 *                                   线程部分									   *
 ***************************************************************************************/
typedef struct status_s {
	int num; // 子线程的个数
	pthread_t* thread_id;// 线程的id

	queue_t queue;

	pthread_mutex_t lock;
	pthread_cond_t cond;

	int exit_flag;// 退出标记位: 0正常, 1要求退出 
}status_t;//线程初始化函数

//线程主函数
void* thread_main(void* p);

// 初始化共享的数据
int init_status(status_t* status, int num);

// 启动子线程
int init_thread(status_t* status);

// 启动socket监听
int init_socket(int* socket_fd, char* port, char* ip);

// 添加epoll监听
int add_epoll(int epoll_fd, int fd);

// 和客户端进行通信
int do_worker(int net_fd);
//宏函数实现日志文件
#define MAX_MSG_SIZE 256//
typedef enum{
    DEBUG,
    INFO,
    WARNING,
    ERROR
}log_level;//日志等级
           

// 宏定义日志记录
#define LOG_MSG(level, msg)  { \
    char log_file_name[20]; \
    if (level == DEBUG) strcpy(log_file_name, "debug.log"); \
    else if (level == INFO) strcpy(log_file_name, "info.log"); \
    else if (level == WARNING) strcpy(log_file_name, "warning.log"); \
    else if (level == ERROR) strcpy(log_file_name, "error.log"); \
    \
    int log_fd = open(log_file_name, O_WRONLY | O_CREAT | O_APPEND, 0644); \
    char buff[MAX_MSG_SIZE]; \
    snprintf(buff, sizeof(buff), "%s: %s: %d: %s \n", \
             __FILE__, __FUNCTION__, __LINE__,msg); \
    \
    write(log_fd, buff, strlen(buff)); \
    close(log_fd); \
} 

/***************************************************************************************
 *                                  10.19讨论添加部分								   *
 ***************************************************************************************/
typedef enum {
	LS,
	CD,
	PUTS,
	GETS,
	REMOVE,
	PWD,
}command_type;//命令的类型
/*
 * @Author:yhy
 * @LastAusthor : yhy
 */
typedef struct user_s {
	char* user_name;
	char* password;
	int flag;//标记该用户有没有注册
	char* path;//用户文件路径
	bool status_signin;//判断用户是否登入
    char* user_id;
}user_t;//用户的信息

typedef struct command_s {
	char buf[1000];//存储命令
	command_type types;//命令类型
	int token_num;//命令参数的数量
}command_t;//命令的信息

// shell命令函数

/***************************************************************************************
 *                                老师定义日常使用部分								    *
 ***************************************************************************************/

#define SIZE(a) (sizeof(a)/sizeof(a[0]))//取数组大小

#define ARGS_CHECK(argc, n) { \
	if (argc != n) { \
		fprintf(stderr, "ERROR: expected %d arguments.\n", n); \
		exit(1); \
	} \
}//命令行参数的检验

#define ERROR_CHECK(retval, val, msg) { \
	if (retval == val) { \
		perror(msg); \
		exit(1); \
	} \
}//错误检查
 //函数是老师定义的，也可以用error

#define THREAD_ERROR_CHECK(ret, msg) { \
	if(ret != 0) { \
		fprintf(stderr, "%s:%s \n", msg, strerror(ret)); \
	} \
}//线程的错误检查函数  

typedef void (*sighandler_t)(int);//信号处理函数

/***************************************************************************************
 *                                注册、登入、退出								    *
 ***************************************************************************************/
/*
 * @Author:yhy
 * @LastAuthor:yhy
 */
bool sign_in(int serviceId, user_t* user);
bool sign_up(int serviceId);
/***************************************************************************************
 *                                用户部分								    *
 ***************************************************************************************/
/*
 * @Author:yhy
 * @LastAuthor:yhy
 */
user_t* userInit();

/***************************************************************************************
*                                            命令                                      *
***************************************************************************************/
//ls命令实现
int lsCommand(command_t* task,user_t* user,int fd);
//pwd命令实现
int rmCommand(command_t* task,char* args,int fd);
//rm命令实现
int removefile(int net_fd, char* file_type);
//发送command的buf
/* void snd_cmd(int fd,command_t* command); */
//接收command的buf
void rcv_cmd(int fd,command_t* command);

int changedir(user_t* user,char* path, int net_fd);

void pwdCommand(command_t * task,user_t* user);

void snd_cmd(int fd,command_t* command, user_t* user,char* arg);

 int get_client(int netfd, char *path);
